	
//
// 130724 - AH - (Paris) Created.
//

package org.bisonservice;

import java.io.IOException;
import java.net.URLEncoder;
import java.sql.Connection;
import java.util.List;

import org.japril.gim.Item;
import org.japril.gim.Items;
import org.japril.gim.sql.SqlItems;

/**
 * <p>
 *   Object that access RDBMS system that store bison location information. 
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class BisonAccess
{
  private final Items m_items;
  
  /**
   * <p>
   *   Constructor.
   * </p<
   * @param con Connection to database to use.
   * @throws IOException If fails.
   */
  public BisonAccess(Connection con) throws IOException
  {
    if (con==null)
    {
      throw new NullPointerException("con");
    }
    
    m_items=new SqlItems(con);
  }
  
  // Edit
  
  /**
   * <p>
   *   Creates
   *   {@link Item} representing bison.
   * </p>
   * @return {@link Item} representing created bison.
   * @throws IOException If fails.
   */
  public Item create() throws IOException { return m_items.create("bison"); }
  
  /**
   * <p>
   *   Creates
   *   {@link Item} representing bison.
   * </p>
   * @param mime MIME type of original data.
   * @param uri  URI of original data.
   * @return {@link Item} representing created bison.
   * @throws IOException If fails.
   */
  public Item create(String mime, String uri) throws IOException
  {
    if (mime==null)
    {
      throw new NullPointerException("mime");  
    }
    if (uri==null)
    {
      throw new NullPointerException("uri");  
    }
    
    Item retVal=create();
    setOriginal(retVal, mime, uri);
    return retVal;
  }
  
  /**
   * <p>
   *   Creates
   *   {@link Item} representing bison.
   * </p>
   * @param mime             MIME type of original data.
   * @param uri              URI of original data.
   * @param mimeTransformed  MIME type of transformed data.
   * @param uriTransformed   URI of transformed data.
   * @return {@link Item} representing created bison.
   * @throws IOException If fails.
   */
  public Item create(String mime, String uri, String mimeTransformed, 
    String uriTransformed) throws IOException
  {
    if (mime==null)
    {
      throw new NullPointerException("mime");  
    }
    if (uri==null)
    {
      throw new NullPointerException("uri");  
    }
    if (mimeTransformed==null)
    {
      throw new NullPointerException("mimeTransformed");  
    }
    if (uriTransformed==null)
    {
      throw new NullPointerException("uriTransformed");  
    }
    
    Item retVal=create();
    setOriginal(retVal, mime, uri);
    setTransformed(retVal, mimeTransformed, uriTransformed);
    return retVal;
  }
  
  /**
   * <p>
   *   Sets bison's MIME and URI for original data.
   * </p>
   * @param bison {@link Item} representing the bison.
   * @param mime  MIME type of original data.
   * @param uri   URI of original data.
   * @throws IOException If fails.
   */
  public void setOriginal(Item bison, String mime, String uri)
    throws IOException
  {
    if (bison==null)
    {
      throw new NullPointerException("bison");
    }
    if (mime==null)
    {
      throw new NullPointerException("mime");  
    }
    if (uri==null)
    {
      throw new NullPointerException("uri");  
    }
    
    m_items.setProperty(bison, "uri", uri);
    m_items.setProperty(bison, "mime_type", mime);
  }
  
  /**
   * <p>
   *   Sets bison's MIME and URI for transformed data.
   * </p>
   * @param bison {@link Item} representing the bison.
   * @param mime  MIME type of transformed data.
   * @param uri   URI of transformed data.
   * @throws IOException If fails.
   */
  public void setTransformed(Item bison, String mime, String uri)
    throws IOException
  {
    if (bison==null)
    {
      throw new NullPointerException("bison");
    }
    if (mime==null)
    {
      throw new NullPointerException("mime");  
    }
    if (uri==null)
    {
      throw new NullPointerException("uri");  
    }
    
    m_items.setProperty(bison, "mime_type_transformed", mime);
    m_items.setProperty(bison, "uri_transformed", uri);
  }
  
  // Query
  
  /**
   * <p>
   *   Gets data associated with bison given it's key.
   * </p>
   * @param item {@link Item} representing the bison.
   * @return Array of at least length {@code 2}.
   * @throws IOException If fails.
   */
  public String[] getBisonData(Item item) throws IOException
  {
    if (item==null)
    {
      throw new NullPointerException("item"); 
    }
    
    return getBisonLocation(item.getId());
  }
  
  /**
   * <p>
   *   Gets location associated with bison given its key.
   * </p>
   * @param key Key.
   * @return Array of length {@code 4} where first is original URI, second is 
   *         original MIME type, the third the transformed URI and the fourth 
   *         is the transformed MIME.
   * @throws IOException If fails.
   */
  public String[] getBisonLocation(int key) throws IOException
  {
    String mime=m_items.getStringProperty(key, "mime_type");
    String uri=m_items.getStringProperty(key, "uri");
    String uriTransformed=m_items.getStringProperty(key, "uri_transformed");
    if (uriTransformed!=null)
    {
      String mimeTransformed=m_items.getStringProperty(key, "uri_transformed");
      return new String[]{ uri, mime, uriTransformed, mimeTransformed };
    }
    return new String[]{ mime, uri, mime, uri };
  }
  
  /**
   * <p>
   *   Gets location associated with bison given its URI.
   * </p>
   * @param key Key.
   * @return Array of length {@code 4} where first is original URI, second is 
   *         original MIME type, the third the transformed URI and the fourth 
   *         is the transformed MIME.
   * @throws IOException If fails.
   */
  public String[] getBisonLocationFromUri(String uri) throws IOException
  {
	if (uri==null)
	{
	  throw new NullPointerException("uri");
	}
	
	Item item=m_items.getItemWithProperty("uri", uri, "bison");
	return item==null ? null : getBisonData(item);
  }
  
  /**
   * <p>
   *   Gets location associated with bison given its transformed URI.
   * </p>
   * @param key Key.
   * @return Array of length {@code 4} where first is original URI, second is 
   *         original MIME type, the third the transformed URI and the fourth 
   *         is the transformed MIME.
   * @throws IOException If fails.
   */
  public String[] getBisonLocationFromTransformedUri(String transformedUri)
    throws IOException
  {
	if (transformedUri==null)
    {
      throw new NullPointerException("uri");
    }
		
    Item item=m_items.getItemWithProperty("uri_transformed", transformedUri, 
      "bison");
    if (item!=null)
    {
      return getBisonData(item);
    }
    else
    {
      item=m_items.getItemWithProperty("uri", transformedUri, "bison");
      if (item==null) return null;
      String[] loc=getBisonData(item);
      if (loc[0].equals(loc[2])) return loc;
      return null;
    }
  }
  
  /**
   * <p>
   *   Stores bison location as received from client.
   * </p>
   * @param br Represents data received from clients.
   * @throws IOException If fails.
   */
  public void store(BisonReceived br) throws IOException
  {
    if (br==null)
	{
      throw new NullPointerException("br");
    }
	
    String uri=br.getOriginalUri();
	
    uri=code(uri);
	
    String mime=br.getOriginalMime();
	
    System.err.println("BisonAccess, store, uri: "+uri);
    System.err.println("BisonAccess, store, mime: "+mime);
	
    if (br.isTransformed())
    {
      String turi=br.getOriginalUri();
      turi=code(turi);
      String tmime=br.getTransformedUri();
      create(mime, uri, tmime, turi);
    }
    else
    {
      create(mime, uri);
    }
  }
  
  public String[] getBisons() throws IOException
  {
    List<Item> items=m_items.getItems("bison");
    int n=items.size();
    String[] retVal=new String[n];
    for (int i=0; i<n; i++)
    {
       String bison=getBison(items.get(i));
       retVal[i]=bison;
    }
    return retVal;
  }
  
  public String getBison(Item item) throws IOException
  {
    if (item==null)
	{
	  throw new NullPointerException("item");
	}
	
	String[] loc=getBisonData(item);
	StringBuilder sb=new StringBuilder();
	sb.append(loc[2]).append(':').append(loc[3]);
	return sb.toString();
  }
  
  private String code(String uri) throws IOException 
  {
    uri=(uri==null) ? "" : uri.trim();
    int idx=uri.indexOf(":");
    if (idx==-1) return URLEncoder.encode(uri, "ISO-8859-1");
    String pre=uri.substring(0, idx);
    String post=uri.substring(idx+1, uri.length());
    return new StringBuilder(pre).append(':')
      .append(URLEncoder.encode(post, "ISO-8859-1")).toString();
  }
  
}
